package opencv.service;


import static com.googlecode.javacv.jna.cxcore.cvCopy;
import static com.googlecode.javacv.jna.cxcore.cvCreateImage;
import static com.googlecode.javacv.jna.cxcore.cvGetSize;
import static com.googlecode.javacv.jna.cxcore.cvReleaseImage;

import java.util.ArrayList;
import java.util.List;

import com.googlecode.javacv.FrameGrabber;
import com.googlecode.javacv.JavaCvErrorCallback;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.jna.cxcore.IplImage;

/**
 * @author Aakash Polra
 */
public class Application  implements Runnable {

	public static final float DEFAULT_FPS = 30f;
	
//	private int camera; // integer id of the camera to use for detection (e.g. 0, 1 etc)
	protected List<Algorithm> algorithms;
	
	// this is now in Algorithm, not here in Application
//	private boolean showOutput; // whether to show debug output image or not. True will cause the call of an appropriate method

	private boolean isRunning = false;
	private boolean stopRequested = false;
	protected long sleepInterval;	//in milliseconds

	protected FrameGrabber grabber;

	public Application() {
		this(new OpenCVFrameGrabber(0), DEFAULT_FPS);
	}

	public Application(FrameGrabber grabber, float fps) {
	
		new JavaCvErrorCallback().redirectError();

		this.algorithms = new ArrayList<Algorithm>();
		this.grabber = grabber;
		this.isRunning = false;
		this.stopRequested = false;
		this.sleepInterval = (long)(1000f/fps);
	}

	public void start() {
		if (!isRunning) {
			this.stopRequested = false;
			new Thread(this).start();
		}
	}

	public void stop() {
		this.stopRequested = true;
	}

	@Override
	public void run() {
		this.isRunning = true;
		
		try {
		//
//		final CvCapture camCapture = cvCreateCameraCapture(camera);
		grabber.start();
		IplImage frame;
			frame = grabber.grab();
		IplImage lastFrame = null;
		
		while (!stopRequested) {
			frame = grabber.grab(); //cvQueryFrame(camCapture);
			
			if (frame != null && lastFrame != null) {
				
//				cvSmooth(frame, frame, CV_GAUSSIAN, 3, 0, 0, 0);
				
				for(Algorithm a : algorithms) {
					a.run(lastFrame, frame);
				}
				onAfterAlgorithmsRan(lastFrame, frame);
				cvReleaseImage(lastFrame.pointerByReference());
			}
			lastFrame = cvCreateImage(cvGetSize(frame), frame.depth, frame.nChannels);
			cvCopy(frame, lastFrame);

			//
			try {
				Thread.sleep(sleepInterval);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		//
//		cvReleaseCapture(camCapture.pointerByReference());
		} catch (Exception e1) {
			e1.printStackTrace();
		} //cvQueryFrame(camCapture);
		
		this.isRunning = false;
	}

	public void onAfterAlgorithmsRan(IplImage lastFrame, IplImage currentFrame) {
		// override if needed
	}
	
	public float getFPS()
	{
		return 1000f/sleepInterval;
	}
	
	public FrameGrabber getGrabber() {
		return grabber;
	}

	public boolean isRunning() {
		return isRunning;
	}

	public List<Algorithm> getAlgorithms() {
		return algorithms;
	}

	public long getSleepInterval() {
		return sleepInterval;
	}

	public void setSleepInterval(long sleepInterval) {
		this.sleepInterval = sleepInterval;
	}
}
